# 0. 安装openCV
'''
Anacoda Prompt: pip install opencv-python
'''

# 1. 使用
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img1 = cv.imread('img1.png', 0)

# 根据图片创建窗口
def In1():
  cv.imshow('image', img1)
  cv.waitKey(0) # 程序等待，直到有按键事件才执行后续
  cv.destroyAllWindows()

# 创建窗口再加载图片

def In2():
  cv.namedWindow('image', cv.WINDOW_NORMAL)
  cv.imshow('image', img1)
  cv.waitKey(0)
  cv.destroyAllWindows()
# In2()

# 写入/保存图像
def In3():
  cv.imshow('image', img1)
  k = cv.waitKey(0)
  if k == 27:
    cv.destroyAllWindows()
  elif k == ord('s'):
    cv.imwrite('img1gray.png', img1)
    cv.destroyAllWindows()
# In3()

def In4():
  plt.imshow(img1, cmap='gray', interpolation='bicubic')
  plt.xticks([]), plt.yticks([])
  plt.show()
# In4()

# 2. 图像入门
# 从相机读取视频
def In5():
  cap = cv.VideoCapture(0)
  if not cap:
    print('cannot open camera')
    exit()
  while True:
    # 逐帧捕获
    ret, frame = cap.read()
    # 如果正确读取帧，ret为True
    if not ret:
      print("Can't receive frame (stream end?). Exiting ...")
      break
    # 我们在框架上的操作到这里
    gray = cv.cvtColor(frame, cv.COLOR_BGR2BGRA)
    # gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    # 显示结果帧e
    cv.imshow('frame', gray)
    if cv.waitKey(1) == ord('q'):
      break
  # 完成所有操作后，释放捕获器
  cap.release()
  cv.destroyAllWindows()
# In5()

# 从文件播放视频
def In6():
  cap = cv.VideoCapture('1.mp4')
  while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
      print("Can't receive frame (stream end?). Exiting ...")
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    cv.imshow('frame', gray)
    if cv.waitKey(18) == ord('q'):
      break
  cap.release()
  cv.destroyAllWindows()
# In6()

# 保存视频
# 在从摄像机捕获的代码下面，沿垂直方向翻转每一帧并保存
def In7():
  cap = cv.VideoCapture(0)
  # 定义编解码器并创建VideoWriter对象
  fourcc = cv.VideoWriter_fourcc(*'XVID')
  out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
  while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
      print("Can't receive frame (stream end?). Exiting ...")
      break
    frame = cv.flip(frame, 0)
    # 写翻转的框架
    out.write(frame)
    cv.imshow('frame', frame)
    if cv.waitKey(1) == ord('q'):
      break
  cap.release()
  out.release()
  cv.destroyAllWindows()
# In7()

# 3. 绘图功能
'''
目标
学习使用OpenCV绘制不同的几何形状
您将学习以下功能：cv.line()，cv.circle()，cv.rectangle()，cv.ellipse()，cv.putText()等。
'''
def In8():
  img = np.zeros((512,512,3), np.uint8)
  # 画直线
  cv.line(img, (0,0), (511,511), (255,0,0), 5)
  # 画矩形
  cv.rectangle(img, (384, 0), (510, 128), (0,255,0), 3)
  # 画圆圈
  cv.circle(img, (447, 63), 63, (0,0,255), -1)
  # 画椭圆
  cv.ellipse(img,(256,256),(100,50),0,0,360,255,-1)
  # 画多边形
  pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
  pts = pts.reshape((-1,1,2))
  cv.polylines(img,[pts],True,(0,255,255))
  # 文字
  font = cv.FONT_HERSHEY_SIMPLEX
  cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA)
  # 展示
  cv.imshow('image', img)
  cv.waitKey(0) 
  cv.destroyAllWindows()

# 鼠标作为画笔 cv.setMouseCallback()
  

# 颜色
def In9():
  cap = cv.VideoCapture(0)
  while(1):
    # 读取帧
    _, frame = cap.read()
    # 转换颜色空间 BGR 到 HSV
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    # 定义HSV中蓝色的范围
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])
    # 设置HSV的阈值使得只取蓝色
    mask = cv.inRange(hsv, lower_blue, upper_blue)
    # 将掩膜和图像逐像素相加
    res = cv.bitwise_and(frame,frame, mask= mask)
    cv.imshow('frame',frame)
    cv.imshow('mask',mask)
    cv.imshow('res',res)
    k = cv.waitKey(5) & 0xFF
    if k == 27:
      break
  cv.destroyAllWindows()
# In9()

# cv.matchTemplate()，cv.minMaxLoc()
def In10():
  img_url = './assets/img/mario.png'
  coin_url = './assets/img/mario_coin.png'
  img_rgb = cv.imread(img_url)
  img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
  template = cv.imread(coin_url,0)
  w, h = template.shape[::-1]
  res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
  threshold = 0.8
  loc = np.where( res >= threshold)
  for pt in zip(*loc[::-1]):
    cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
    cv.imwrite('res.png',img_rgb)
In10()